/*
 * @Author: wuqingchun
 * @Date: 2024-04-09 22:36:24
 * @Description: 右值和右值引用
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-04-11 16:22:39
 */
#include <iostream>
#include <vector>

struct PERSON_INFO
{
    char szID[32];
    char szName[16];
    int iAge;
};


// 分数类定义
class Fraction
{
public:
    Fraction(int iNumerator, int iDenominator):
        m_iNumerator(iNumerator),
        m_iDenominator(iDenominator)
    {
        std::cout << "Fraction" << std::endl;
    }

    ~Fraction()
    {
        std::cout << "~Fraction" << std::endl;
    }

    void Show()
    {
        std::cout << m_iNumerator << "/" << m_iDenominator << std::endl;
    }
    
private:
    int m_iNumerator {0};   // 分子
    int m_iDenominator {1}; // 分母
};


void test_left_value()
{
    std::cout << "====== left value begin ======" << std::endl;
    
    int iValue = 100;
    // 可以对变量 iValue 取地址，变量 iValue 是一个左值
    int* piValue = &iValue;

    // 对指针进行解引用，然后进行赋值
    *piValue = 200;
    int* piPtr = &*piValue;

    int aiValues[5] = {1, 2, 3, 4, 5};
    // 对数组元素取地址，数组元素是左值
    int* piElem = &aiValues[4];

    // 对数组名取地址，数组名是左值
    int** piArrName = (int**)&aiValues;

    PERSON_INFO stPerson;
    // 对结构体成员取地址，结构体成员是左值
    int *piAge = &stPerson.iAge;

    std::cout << "  iValue: " << &iValue << ", " << iValue << std::endl;
    std::cout << " piValue: " << &piValue << ", " << piValue << ", " << *piValue << std::endl;
    std::cout << "   piPtr: " << &piPtr << ", " << piPtr << ", " << *piPtr << std::endl;

    std::cout << "   aiValues[0]: " << &aiValues[0] << ", " << aiValues[0] << std::endl;
    std::cout << "      aiValues: " << &aiValues << ", " << aiValues << std::endl;
    std::cout << " stPerson.iAge: " << &stPerson.iAge << ", " << stPerson.iAge << std::endl;

    std::cout << "====== left value end ======" << std::endl;
}

void test_right_value()
{
    std::cout << "====== right value begin ======" << std::endl;
    10;            // 整型字面量
    "Hello world"; // 字符串字面量

    PERSON_INFO(); // 临时对象
    std::cout << "====== right value end ======" << std::endl;
}


void test_lvalue_reference()
{
    int iValue = 10;
    const int iValue2 = 100;

    // 编译错误
    //  error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
    //int &refValue = iValue2;

    // 左值引用只能用 不能修改的左值进行初始化
    int &refValue1 = iValue;

    // const 左值引用，可以用右值初始化
    const int &refValue21 = 10; 
    // const 左值引用，可以用可修改的左值初始化
    const int &refValue22 = iValue; 
    // const 左值引用，可以不可修改的左值初始化
    const int &refValue23 = iValue2;
}

void test_rvalue_reference1()
{
    Fraction(3,5);
    std::cout << "============" << std::endl;
}

void test_rvalue_reference2()
{
    int &&refLiteral = 10;

    std::cout << refLiteral << std::endl;
    refLiteral = 20;
    std::cout << refLiteral << std::endl;

    // 作为一个匿名对象，Fraction（3,5）通常会在定义它的表达式的末尾超出范围。
    // 但是，由于我们用它初始化一个右值引用，它的持续时间会延长到块的结尾。
    // 然后我们可以使用该右值引用来输出Fraction的值。
    Fraction &&refFraction = Fraction(3,5);
    std::cout << "============" << std::endl;
    refFraction.Show();
}


void test_move()
{
    std::vector<int> vecAA = {1, 2, 3};
    std::vector<std::vector<int>> vecBB;

    std::cout <<"vecAA.size: " << vecAA.size() << std::endl;

    vecBB.push_back(std::move(vecAA));

    std::cout <<"vecAA.size: " << vecAA.size() << std::endl;
}

void show(int&& refValue)
{
    std::cout << refValue << std::endl;
}

void show(int*&& refValue)
{
    std::cout << refValue << std::endl;
}

int main(int argc, char** argv)
{
    int iLeftValue = 10;

    //show(iLeftValue);

    show((int&&)iLeftValue);
    show(std::move(iLeftValue));

    show(20);
    show(iLeftValue + 30);

    int iLeftValue2 = 100;

    show(iLeftValue + iLeftValue2);

    int aiValues[5] = {1, 2, 3, 4, 5};
    show(aiValues);

    //aiValues = 100;
    int** piArrName = (int**)&aiValues;


    test_left_value();
    test_rvalue_reference1();
    test_rvalue_reference2();

    test_move();
    return 0;
}